package com.woniuxy.gateway.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.commons.enums.ResultEnum;
import com.woniuxy.commons.enums.TokenEnum;
import com.woniuxy.commons.util.JwtUtil;
import com.woniuxy.commons.util.ResponseResult;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

/**
 * @Author zhangyong
 * @Date 2021/8/4 0004
 */
//@Component // 加入ioc容器
public class CustomFilter implements GlobalFilter, Ordered {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    //执行过滤的方法，作用与zuul中的run方法一样
    //参数1：网络服务交换机  参数2：过滤器链
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取request
        ServerHttpRequest request = exchange.getRequest();

        //2.获取请求头(token)
        List<String> tokens = request.getHeaders().get("authorization");
        List<String> refreshtokens = request.getHeaders().get("refreshtoken");
        String token = null;
        String refreshtoken = null;
        //判断
        if (tokens != null && tokens.size() != 0){
            token = tokens.get(0);
            System.out.println("进来了吗");
        }
        if(refreshtokens != null && refreshtokens.size() != 0){
            refreshtoken = refreshtokens.get(0);
        }

        //3.获取uri
        String uri = request.getURI().getPath();
        System.out.println(uri);

        //判断是否需要登录操作进行操作
        if(!requireAuth(uri)){
            //放行
            System.out.println("不需要认证，直接放行");
            return chain.filter(exchange);
        }

        //4.执行到此处，说明需要认证
        System.out.println("需要认证，验证token");
        if(refreshtoken == null || token == null){
            System.out.println("refreshtoken或者token为空");
            //没登录
            DataBuffer dataBuffer = result(exchange);
            //中断
            return exchange.getResponse().writeWith(Mono.just(dataBuffer));
        }

        //执行到此处说明refreshtoken，token都有，判断token是否合法
        //5.判断refreshtoken是否合法 判断redis中是否有这个refreshtoken这个key 如果有说明合法
        if(redisTemplate.hasKey(refreshtoken)){
            //合法
            System.out.println("refreshtoken合法");
        }else{
            System.out.println("refreshtoken不合法");
            //refreshtoken不合法
            DataBuffer dataBuffer = result(exchange);
            //中断
            return exchange.getResponse().writeWith(Mono.just(dataBuffer));
        }


        //6.判断token是否合法
        if (JwtUtil.verify(token) == TokenEnum.TOKEN_BAD){
            System.out.println("token不合法");
            //伪造  不合法   中断请求
            //得到数据
            DataBuffer dataBuffer = result(exchange);
            //中断
            return exchange.getResponse().writeWith(Mono.just(dataBuffer));
           
        }else if (JwtUtil.verify(token) == TokenEnum.TOKEN_EXPIRE){
            //过期 生成新的token 返回给前端 请求不中断
            System.out.println("token 过期，重新生成token");
            //从token中获取账号
            String account = JwtUtil.getUname(token);
            //通过账号重新生成token
            token = JwtUtil.generateToken(account);
            //返回给浏览器
            exchange.getResponse().getHeaders().add("authorization",token);
            //暴露头
            exchange.getResponse().getHeaders().add("Access-Control-Expose-Headers","authorization");

            //通过refreshtoken找到redis中的token，并修改

        }

        //执到这一步 说明token合法
        System.out.println("token合法，放行请求");

        //假设访问goods开头的需要登录，假设当前用户没登录，应该返回json提示，而且当前请求终止
        //获取response




        //放行，交给下一个过滤器执行过滤
        return chain.filter(exchange);
    }

    //指定执行顺序：值越小先执行，可以是负数
    @Override
    public int getOrder() {
        return 0;
    }

    //返回bool值，是否需要登录
    private Boolean requireAuth(String uri){
        //存存放不需要认证的uri
        List<String> uris = Arrays.asList(
                "/auth/login","/auth/regist","/file/upload"
        );

        //遍历uri
        for (String str : uris) {
            if (uri.startsWith(str)){
                //不需要认证
                return false;
            }
        }
        //需要认证
        return true;
    }

    //返回结果方法
    private DataBuffer result(ServerWebExchange exchange){
        //1.获取response对象
        ServerHttpResponse response = exchange.getResponse();
        //2.创建result对象
        ResponseResult<String> responseResult = new ResponseResult<>();
        responseResult.setCode(500);
        responseResult.setStatus(ResultEnum.NO_LOGIN);
        responseResult.setMessage("请登录");
        try {
            //3.转json
            String json = new ObjectMapper().writeValueAsString(responseResult);
            //4.转byte[]
            byte[] data = json.getBytes(StandardCharsets.UTF_8);//指定字符编码
            //5.将byte[]数据存放发到缓冲区
            DataBuffer dataBuffer = response.bufferFactory().wrap(data);
            //6.设置响应头
            response.getHeaders().add("Content-Type","application/json;charset=utf-8");
            //7.写出数据，并结束请求
            return dataBuffer;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
